import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_app_demo/ui_demo/ui3dcard/card.dart';
import 'package:flutter_app_demo/podo/card_model.dart';

class MyCardFlipper extends StatefulWidget {
    
    final List<CardViewModel> cards;
    
    final Function onScroll;
    
    MyCardFlipper({ @required this.cards, @required this.onScroll});
    
    @override
    _MyCardFlipperState createState() => _MyCardFlipperState();
}

class _MyCardFlipperState extends State<MyCardFlipper> with TickerProviderStateMixin<MyCardFlipper> {
    
    double scrollPercent = 0.0;
    Offset startDrag;
    double startDragScrollPercent;
    
    double finishingScrollStart;
    double finishingScrollEnd;
    AnimationController finishingScrollController;
    
    @override
    void initState() {
        super.initState();
        finishingScrollController = new AnimationController(
            duration: const Duration(milliseconds: 150),
            vsync: this,
        )
            ..addListener(() {
                setState(() {
                    scrollPercent = lerpDouble(finishingScrollStart, finishingScrollEnd, finishingScrollController.value);
                    if (widget.onScroll != null) {
                        widget.onScroll(scrollPercent);
                    }
                });
            });
    }
    
    @override
    void dispose() {
        finishingScrollController.dispose();
        super.dispose();
    }
    
    void _onHorizontalDragStart(DragStartDetails details) {
        startDrag = details.globalPosition;
        startDragScrollPercent = scrollPercent;
    }
    
    void _onHorizontalDragUpdate(DragUpdateDetails details) {
        final currentDrag = details.globalPosition;
        final dragDistance = currentDrag.dx - startDrag.dx;
        final singleCardScrollPercent = dragDistance / context.size.width;
        
        final cardCount = widget.cards.length;
        
        setState(() {
            scrollPercent = (startDragScrollPercent - singleCardScrollPercent / cardCount).clamp(0.0, 1.0 - 1 / cardCount); //最后一张卡片不需要划出屏幕外，所以此处需要1.0 - 1 / cardCount
            
            if (widget.onScroll != null) {
                widget.onScroll(scrollPercent);
            }
        });
    }
    
    void _onHorizontalDragEnd(DragEndDetails details) {
        final cardCount = widget.cards.length;
        
        finishingScrollStart = scrollPercent;
        finishingScrollEnd = (scrollPercent * cardCount).round() / cardCount;
        finishingScrollController.forward(from: 0.0);
        
        setState(() {
            startDrag = null;
            startDragScrollPercent = null;
        });
    }
    
    Matrix4 _buildCardProjection(double scrollPercent) {
        //http://web.iitd.ac.in/~hegde/cad/lecture/L9_persproj.pdf
        //http://www.opengl-tutorial.org/cn/beginners-tutorials/tutorial-3-matrices/
        
        final perspective = 0.002;
        final radius = 1.0;
        final angle = scrollPercent * pi / 8;
        final horizontalTranslation = 0.0;
        Matrix4 projection = Matrix4.identity()
            ..setEntry(0, 0, 1 / radius) //
            ..setEntry(1, 1, 1 / radius) //
            ..setEntry(3, 2, -perspective) //
            ..setEntry(2, 3, -radius) //
            ..setEntry(3, 3, perspective * radius + 1.0);
        
        final rotationPointMultiplier = angle > 0 ? angle / angle.abs() : 1.0;
        
        projection = projection //
            * Matrix4.translationValues(horizontalTranslation + (rotationPointMultiplier * 300.0), 0, 0) //
            * Matrix4.rotationY(angle)
            * Matrix4.translationValues(0, 0, radius)
            * Matrix4.translationValues(-rotationPointMultiplier * 300.0, 0, 0)
        
        ;
        
        return projection;
    }
    
    List<Widget> _buildAllCards() {
        final cardCount = widget.cards.length;
//        return [
//            _buildCard(0, 3, scrollPercent),
//            _buildCard(1, 3, scrollPercent),
//            _buildCard(2, 3, scrollPercent),
//        ];
        
        int index = 0;
        return widget.cards.map((CardViewModel cardViewModel) {
            return _buildCard(cardViewModel, index++, cardCount, scrollPercent); //注意这里的return！！！
        }).toList();
    }
    
    Widget _buildCard(CardViewModel cardViewModel, int cardIndex, int cardCount, double scrollPercent) {
        final cardScrollPercent = scrollPercent * cardCount;
        final parallax = scrollPercent - cardIndex / cardCount;
        
        return FractionalTranslation(
            translation: Offset(cardIndex - cardScrollPercent, 0.0),
            child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Transform(
                    transform: _buildCardProjection(cardScrollPercent - cardIndex),
                    child: MyCard(
                        viewModel: cardViewModel,
                        parallaxPercent: parallax,
                    ),
                ),
            ),
        );
    }
    
    @override
    Widget build(BuildContext context) {
        return GestureDetector(
            
            onHorizontalDragStart: _onHorizontalDragStart,
            onHorizontalDragUpdate: _onHorizontalDragUpdate,
            onHorizontalDragEnd: _onHorizontalDragEnd,
            
            // 点击stack的padding时也应该触发触摸事件
            behavior: HitTestBehavior.translucent,
            
            child: Stack(
                children: _buildAllCards(),
            ),
        );
    }
    
}
